package com.xinqi.modules.exam.student.convert;

import com.xinqi.common.base.dto.QuestionBaseDTO;
import com.xinqi.common.base.enums.QuestionTypeEnum;
import com.xinqi.common.base.enums.YesNoEnum;
import com.xinqi.common.base.utils.lambda.Lambdas;
import com.xinqi.common.mapstruct.CommonConvertConfig;
import com.xinqi.modules.exam.paper.domain.CourseExamPaperConfigEntity;
import com.xinqi.modules.exam.paper.domain.CourseExamPaperEntity;
import com.xinqi.modules.exam.paper.enums.ExamRandomStrategyEnum;
import com.xinqi.modules.exam.student.domain.CourseExamPaperStudentEntity;
import com.xinqi.modules.exam.student.dto.PaperAnswerDTO;
import com.xinqi.modules.exam.student.dto.PaperAnswerDetailDTO;
import com.xinqi.modules.exam.student.dto.req.CourseExamPaperStudentCreateDTO;
import com.xinqi.modules.exam.student.dto.req.CourseExamPaperStudentUpdateDTO;
import com.xinqi.modules.exam.student.dto.rsp.CourseExamPaperStudentDetailDTO;
import com.xinqi.modules.exam.student.dto.rsp.CourseExamPaperStudentResultDTO;
import com.xinqi.modules.exam.student.enums.PaperAnswerStatusEnum;
import org.apache.commons.collections4.CollectionUtils;
import org.mapstruct.AfterMapping;
import org.mapstruct.Context;
import org.mapstruct.Mapper;
import org.mapstruct.MappingTarget;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * 课程测评学生答题转换
 *
 * @author: linkai
 * @date: 2023/07/02
 */
@Mapper(config = CommonConvertConfig.class)
public abstract class CourseExamPaperStudentConvert {
    public abstract CourseExamPaperStudentEntity create(CourseExamPaperStudentCreateDTO s);

    public abstract CourseExamPaperStudentEntity update(CourseExamPaperStudentUpdateDTO s, @MappingTarget CourseExamPaperStudentEntity t);

    public abstract CourseExamPaperStudentEntity update(CourseExamPaperStudentUpdateDTO s);

    public abstract CourseExamPaperStudentResultDTO convert(CourseExamPaperStudentEntity s);

    public abstract CourseExamPaperStudentDetailDTO toDetail(CourseExamPaperStudentEntity s, @Context CourseExamPaperEntity exam);

    public abstract PaperAnswerDetailDTO toDetail(PaperAnswerDTO s);

    @AfterMapping
    public void afterDetail(CourseExamPaperStudentEntity s, @MappingTarget CourseExamPaperStudentDetailDTO t, @Context CourseExamPaperEntity exam) {
        List<PaperAnswerDetailDTO> paperAnswer = t.getPaperAnswer();
        if (CollectionUtils.isEmpty(paperAnswer)) {
            return;
        }
        Map<Long, QuestionBaseDTO> questionMap = exam.getQuestionContent().stream()
            .collect(Collectors.toMap(QuestionBaseDTO::getId, v -> v));
        // 设置试题明细
        paperAnswer.forEach(p -> {
            QuestionBaseDTO question = questionMap.get(p.getQuestionId());
            p.setQuestion(question);
        });
    }

    public CourseExamPaperStudentEntity create(CourseExamPaperEntity exam,
                                               CourseExamPaperConfigEntity config,
                                               Long studentId) {
        CourseExamPaperStudentEntity studentPaper = new CourseExamPaperStudentEntity();
        // 初始属性
        studentPaper.setExamPaperId(exam.getId());
        studentPaper.setClassId(exam.getClassId());
        studentPaper.setStudentId(studentId);
        studentPaper.setStatus(PaperAnswerStatusEnum.未交卷);
        studentPaper.setTotalScore(exam.getTotalScore());
        studentPaper.setQuestionTotal(exam.getQuestionTotal());
        studentPaper.setQuestionTypeTotal(exam.getQuestionTypeTotal());
        studentPaper.setSubjectiveQuestionNum(exam.getSubjectiveQuestionNum());
        studentPaper.setObjectiveQuestionNum(exam.getObjectiveQuestionNum());
        studentPaper.setIsLimitAnswerTime(config.getIsLimitAnswerTime());
        // 是否限时答题
        if (Objects.equals(studentPaper.getIsLimitAnswerTime(), YesNoEnum.YES.ordinal())) {
            studentPaper.setExamDuration(config.getAnswerDuration());
            studentPaper.setRemainingAnswerTime(config.getAnswerDuration());
        } else {
            studentPaper.setExamDuration(0L);
            studentPaper.setRemainingAnswerTime(0L);
        }
        // 创建学生试题
        studentPaper.setPaperAnswer(create(exam.getQuestionContent(), config.getExamRandomStrategy()));
        return studentPaper;
    }

    public List<PaperAnswerDTO> create(List<QuestionBaseDTO> questionList, ExamRandomStrategyEnum examRandomStrategy) {
        List<PaperAnswerDTO> paperAnswerList;
        switch (examRandomStrategy) {
            case 全部题目顺序随机:
                paperAnswerList = Lambdas.randomList(questionList, this::create);
                break;
            case 同一题型内题目顺序随机:
                paperAnswerList = new ArrayList<>(questionList.size());
                Map<String, List<QuestionBaseDTO>> questionMap = questionList.stream()
                    .collect(Collectors.groupingBy(QuestionBaseDTO::getType));
                // 循环 试题类型
                Stream.of(QuestionTypeEnum.values()).forEach(type -> {
                    List<QuestionBaseDTO> questionListByType = questionMap.get(type.getCode());
                    if (CollectionUtils.isEmpty(questionListByType)) {
                        return;
                    }
                    Optional.ofNullable(Lambdas.randomList(questionListByType, this::create))
                        .ifPresent(paperAnswerList::addAll);
                });
                break;
            default:
                paperAnswerList = Lambdas.convertList(questionList, this::create);
        }
        return paperAnswerList;
    }

    public PaperAnswerDTO create(QuestionBaseDTO question) {
        PaperAnswerDTO paperAnswer = new PaperAnswerDTO();
        paperAnswer.setQuestionId(question.getId());
        paperAnswer.setSort(question.getSort());
        paperAnswer.setQuestionName(question.getQuestion());
        paperAnswer.setQuestionType(question.getType());
        paperAnswer.setScore(question.getScore());
        paperAnswer.setStudentScore(BigDecimal.ZERO);
        paperAnswer.setIsReply(false);
        paperAnswer.setIsRight(false);
        return paperAnswer;
    }
}
